// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Xml;
using Microsoft.TeamFoundation.Migration.Toolkit.Wit;
using System.Runtime.Serialization;
using System.Diagnostics;

namespace Microsoft.TeamFoundation.Migration.Toolkit.Linking
{
    /// <summary>
    /// Artifact with links
    /// </summary>
    public interface ILinkContainer
    {
        /// <summary>
        /// Artifact's URI.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")]
        string Uri { get; }
    }

    /// <summary>
    /// Uniform representation of a complete link.
    /// </summary>
    public interface ILink
    {
        /// <summary>
        /// Returns type name.
        /// </summary>
        string LinkType { get; }

        /// <summary>
        /// Returns source artifact of the link operation.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")]
        string SourceUri { get; set;}

        /// <summary>
        /// Returns target artifact of the link operation.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings")]
        string TargetUri { get; set;}

        /// <summary>
        /// Link's comment.
        /// </summary>
        string Comment { get; }

        /// <summary>
        /// Serializes link's content.
        /// </summary>
        /// <returns></returns>
        string Serialize();

        /// <summary>
        /// Creates a copy of the link that points to the given artifact of the same type.
        /// </summary>
        /// <param name="targetUri">New target artifact</param>
        /// <returns>Link object pointing to the new target</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#")]
        ILink Redirect(
            string targetUri);

        /// <summary>
        /// Updates TFS target with link's data. 
        /// </summary>
        /// <param name="action">Action to do on the link</param>
        /// <param name="target">Link-specific TFS target</param>
        void UpdateTfs(
            AssociationAction action,
            object target);
    }

    /// <summary>
    /// Callback function for enumerating sources of deferred links.
    /// </summary>
    /// <param name="type">Type the link belong to</param>
    /// <param name="sourceUri">URI of the source artifact</param>
    public delegate void EnumerateSourcesCallback(SystemType systemType, string sourceUri);

    /// <summary>
    /// The link engine is the interface through which the linking system is operated.
    /// </summary>
    public interface ILinkEngine
    {
        /// <summary>
        /// Specifies a work item tracking session in whose context the engine will be working.
        /// </summary>
        WorkItemTrackingSession WorkItemTrackingSession { get; set; }

        /// <summary>
        /// Specifies a version control session in whose context the engine will be working.
        /// </summary>
        VersionControlSession VersionControlSession { get; set; }

        /// <summary>
        /// Gets all supported links from the given object.
        /// </summary>
        /// <param name="source">Source container</param>
        /// <returns>List of all supported links</returns>
        ReadOnlyCollection<ILink> GetLinks(
            ILinkContainer source);

        /// <summary>
        /// Defers link for processing it later.
        /// </summary>
        /// <param name="system">System the link belong to</param>
        /// <param name="link">Link to defer</param>
        void Defer(
            SystemType system,
            ILink link);

        /// <summary>
        /// Removes deferred link.
        /// </summary>
        /// <param name="system">System the link belongs to</param>
        /// <param name="link">Link to remove</param>
        void RemoveDeferred(
            SystemType system,
            ILink link);

        /// <summary>
        /// Enumerates all sources of deferred links.
        /// </summary>
        /// <param name="callback">Callback function</param>
        void EnumerateDeferredLinkSources(
            EnumerateSourcesCallback callback);

        /// <summary>
        /// Gets all deferred links originating from the given source.
        /// </summary>
        /// <param name="system">System the source artifact belongs to</param>
        /// <param name="sourceUri">Uri of the source artifact</param>
        /// <returns>List of links</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "1#")]
        ReadOnlyCollection<ILink> GetDeferredLinks(
            SystemType system,
            string sourceUri);

        /// <summary>
        /// Finds reflection of the given artifact.
        /// </summary>
        /// <param name="sourceSystem">System the artifact belongs to</param>
        /// <param name="sourceUri">URI of the source artifact</param>
        /// <returns>URI of the reflection, if any</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "1#")]
        string FindReflection(
            SystemType sourceSystem,
            string sourceUri);

        /// <summary>
        /// Translates artifact's URI and extract tool-specific artifact id from it.
        /// </summary>
        /// <param name="sourceUri">URI of the source artifact</param>
        /// <param name="id">Internal id</param>
        /// <returns>True if URI was translated</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")]
        bool TranslateUri(
            string sourceUri,
            out string id);

        // Linking events
        event EventHandler<LinkingEventArgs> LinkDeferred;
        event EventHandler<MigrationEventArgs> EngineFailure;
    }

    /// <summary>
    /// Handler for artifacts of a certain type.
    /// </summary>
    public interface IArtifactHandler
    {
        /// <summary>
        /// Tries to find reflection of the given artifact.
        /// </summary>
        /// <param name="sourceSystem">System the source artifact belongs to</param>
        /// <param name="sourceUri">URI of the source artifact</param>
        /// <param name="targetId">Tool-specific id of the reflection</param>
        /// <returns>True if the artifact was processed</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "1#")]
        bool TryFindReflection(
            SystemType sourceSystem,
            string sourceUri,
            out string targetId);

        /// <summary>
        /// Tries to translate URI and extract a tool-specific id from it.
        /// </summary>
        /// <param name="uri">URI to translate</param>
        /// <param name="id">Tool-specific id</param>
        /// <returns>True if URI was processed</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#")]
        bool TryTranslateUri(
            string uri,
            out string id);

        /// <summary>
        /// Creates URI from the tool-specific id.
        /// </summary>
        /// <param name="id">Tool-specific id</param>
        /// <returns>URI</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings")]
        string CreateUri(
            string id);
    }


    /// <summary>
    /// Linking event argument type.
    /// </summary>
    public class LinkingEventArgs : EventArgs
    {
        public LinkingEventArgs()
            : this(null)
        {
        }

        public LinkingEventArgs(ILink link)
        {
            m_link = link;
        }


        /// <summary>
        /// The link being operated on at the time of the event.
        /// </summary>
        public ILink Link
        {
            get
            {
                return m_link;
            }
        }

        ILink m_link;
    }
}
